#include "GQueue.h"
#include <stdlib.h>
#include <ctype.h>

#define qCapcityMsk (queue->capcity-1)
/************************************************************************/
/*                                                                      */
/************************************************************************/
/**
  * @brief      判断队列是否为空
  * @param[in]  queue   队列
  *
  * @return     errcode
  * @retval      1      队列为空
  * @retval      0      队列不为空
  * @retval     -1      失败
  */
int gqueue_is_empty(gqueue_t* queue) {
    if(queue == NULL)
    {
        return -1;
    }
    return queue->isEmpty;
}

/**
  * @brief      判断队列是否已满
  * @param[in]  queue   队列
  *
  * @return     errcode
  * @retval      1      队列已满
  * @retval      0      队列未满
  * @retval     -1      失败
  */
int gqueue_is_full(gqueue_t* queue) {
    if(queue == NULL)
    {
        return -1;
    }
    return queue->isFull;
}

/**
  * @brief      获取队列的已用空间
  * @param[in]  queue   队列
  *
  * @return     errcode
  * @retval     >=0     队列的数据数量
  */
size_t gqueue_used_space(gqueue_t* queue) {
    if(queue == NULL)
    {
        return 0;
    }
    if(queue->isFull)
    {
        return queue->capcity;
    }
    return (queue->tail + queue->capcity - queue->head)&qCapcityMsk;
}

/**
  * @brief      获取队列的空闲空间
  * @param[in]  queue   队列
  *
  * @return     errcode
  * @retval     >=0     队列的数据数量
  */
size_t gqueue_free_space(gqueue_t* queue) {
    if(queue == NULL)
    {
        return 0;
    }
    return queue->capcity - gqueue_used_space(queue);
}

/**
  * @brief      数据入队
  * @param[in]  queue   队列
  * @param[in]  item    要入队的数据项
  *
  * @return     errcode
  * @retval      0      成功
  * @retval     -1      参数异常
  * @retval     -2      队列满
  */
int gqueue_push(gqueue_t* queue, void* item) {
    char* charItem = (char*)item;
    if(queue == NULL || item == NULL)
    {
        return -1;
    }
    if(queue->isFull)
    {
        return -2;
    }
    memcpy((char*)queue->base + queue->tail * queue->itemSize, charItem, queue->itemSize);
    queue->tail = (queue->tail + 1)&qCapcityMsk;

    if(queue->tail == queue->head)      //队列满
    {
        queue->isFull = 1;
    }
    queue->isEmpty = 0;
    return 0;
}

/**
  * @brief      多数据入队
  * @param[in]  queue   队列
  * @param[in]  item    要入队的数据项
  * @param[in]  len     要入队的数据项数量
  * @param[out] actualLen    入队的实际数量
  * @return     errcode
  * @retval      0      成功
  * @retval     -1      参数异常
  * @retval     -2      队列满
  */
int gqueue_push_multiple(gqueue_t* queue, void* item, size_t len,size_t* actualLen) {
    char* charItem = (char*)item;
    if(queue == NULL || item == NULL || len == 0)
    {
        return -1;
    }
    if(queue->isFull)
    {
        return -2;
    }
    size_t actual,free;
    free = gqueue_free_space(queue);
    actual = len<free?len:free;
    *actualLen = actual;
    if(queue->itemSize == 1)
    {
        if(queue->tail + actual > queue->capcity)
        {
            size_t lenToEnd = queue->capcity - queue->tail;
            size_t lenFromBegin = actual - lenToEnd;
            memcpy((char*)queue->base + queue->tail,charItem,lenToEnd);
            memcpy((char*)queue->base, charItem+lenToEnd,lenFromBegin);
        }
        else
        {
            memcpy((char*)queue->base + queue->tail, charItem, actual);
        }
    }
    else
    {
        if(queue->tail + actual > queue->capcity)
        {
            size_t lenToEnd = queue->capcity - queue->tail;
            size_t lenFromBegin = actual - lenToEnd;
            memcpy((char*)queue->base + queue->tail*queue->itemSize,charItem,lenToEnd*queue->itemSize);
            memcpy((char*)queue->base, charItem+lenToEnd*queue->itemSize,lenFromBegin*queue->itemSize);
        }
        else
        {
            memcpy((char*)queue->base + queue->tail*queue->itemSize, charItem, actual*queue->itemSize);
        }
    }
    queue->tail = (queue->tail + actual)&qCapcityMsk;

    if(queue->tail == queue->head)      //队列满
    {
        queue->isFull = 1;
    }
    queue->isEmpty = 0;
    return 0;
}

/**
  * @brief      数据出队
  * @param[in]  queue   队列
  * @param[in]  item    要出队的数据项
  *
  * @return     errcode
  * @retval      0      成功
  * @retval     -1      参数异常
  * @retval     -2      队列空
  */
int gqueue_pop(gqueue_t* queue, void* item) {
    if(queue == NULL || item == NULL)
    {
        return -1;
    }
    if(queue->isEmpty)
    {
        return -2;
    }
    memcpy(item, (char*)queue->base + queue->head * queue->itemSize, queue->itemSize);
    queue->head = (queue->head+1)&qCapcityMsk;

    if(queue->tail == queue->head)      //队列已取空
    {
        queue->isEmpty = 1;
    }
    queue->isFull = 0;
    return 0;
}

/**
  * @brief      多数据出队
  * @param[in]  queue   队列
  * @param[in]  item    要出队的数据项
  * @param[in]  len     要出队的数据项数量
  *
  * @return     errcode
  * @retval      0      成功
  * @retval     -1      参数异常
  * @retval     -2      数据不足len的长度,或者队列为空
  */
int gqueue_pop_multiple(gqueue_t* queue, void* item,size_t len) {
    int ret;
    ret = gqueue_peek_multiple(queue,item,len);
    if(!ret)
    {
        queue->head = (queue->head+len)&qCapcityMsk;
        if(queue->tail == queue->head)      //队列已取空
        {
            queue->isEmpty = 1;
        }
        queue->isFull = 0;
    }
    return ret;
}

/**
  * @brief      多数据出队,指定一个最大数量，函数能返回实际数量
  * @param[in]  queue   队列
  * @param[in]  item    要出队的数据项
  * @param[in]  len     要出队的数据项数量
  * @param[out] actualLen 实际取出的数据数量
  * @return     errcode
  * @retval      0      成功
  * @retval     -1      参数异常
  * @retval     -2      数据不足len的长度
  */
int gqueue_pop_multiple_most(gqueue_t* queue, void* item,size_t len,size_t* actualLen){
    int ret;
    ret = gqueue_peek_multiple_most(queue,item,len,actualLen);
    if(!ret)
    {
        queue->head = (queue->head+(*actualLen))&qCapcityMsk;
        if(queue->tail == queue->head)      //队列已取空
        {
            queue->isEmpty = 1;
        }
        queue->isFull = 0;
    }
    return ret;
}

/**
  * @brief      队尾数据出队
  * @param[in]  queue   队列
  * @param[in]  item    要出队的数据项
  *
  * @return     errcode
  * @retval      0      成功
  * @retval     -1      参数异常
  * @retval     -2      队列空
  */
int gqueue_pop_tail(gqueue_t* queue, void* item) {
    if(queue == NULL || item == NULL)
    {
        return -1;
    }
    if(queue->isEmpty)
    {
        return -2;
    }

    //queue->tail指向的是最后一个有效数据的下一个位置
    queue->tail = queue->tail ? queue->tail - 1 : queue->capcity - 1;
    memcpy(item, (char*)queue->base + queue->tail * queue->itemSize, queue->itemSize);

    if(queue->tail == queue->head)
    {
        queue->isEmpty = 1;
    }
    queue->isFull = 0;
    return 0;
}

/**
  * @brief      查看队首的数据
  * @param[in]  queue   队列
  * @param[in]  item    队首的数据项
  *
  * @return     errcode
  * @retval      0      成功
  * @retval     -1      参数异常
  * @retval     -2      队列空
  */
int gqueue_peek(gqueue_t* queue, void* item){
    if(queue == NULL || item == NULL)
    {
        return -1;
    }
    if(queue->isEmpty)
    {
        return -2;
    }

    memcpy(item, (char*)queue->base + queue->head * queue->itemSize, queue->itemSize);
    return 0;
}

/**
  * @brief      多数据出队
  * @param[in]  queue   队列
  * @param[in]  item    要出队的数据项
  * @param[in]  len     要出队的数据项数量
  *
  * @return     errcode
  * @retval      0      成功
  * @retval     -1      参数异常
  * @retval     -2      数据不足len的长度,或者队列为空
  */
int gqueue_peek_multiple(gqueue_t* queue, void* item,size_t len) {
    char* charItem = (char*)item;
    if(queue == NULL || item == NULL || len == 0)
    {
        return -1;
    }
    if(gqueue_used_space(queue)<len || queue->isEmpty)
    {
        return -2;
    }
    if(queue->itemSize == 1)
    {
        if(queue->head + len > queue->capcity)
        {
            size_t lenToEnd = queue->capcity - queue->head;
            size_t lenFromBegin = len - lenToEnd;
            memcpy(charItem,(char*)queue->base+queue->head,lenToEnd);
            memcpy(charItem+lenToEnd,queue->base,lenFromBegin);
        }
        else
        {
            memcpy(charItem,(char*)queue->base+queue->head,len);
        }
    }
    else
    {
        if(queue->head + len > queue->capcity)
        {
            size_t lenToEnd = queue->capcity - queue->head;
            size_t lenFromBegin = len - lenToEnd;
            memcpy(charItem,(char*)queue->base+queue->head*queue->itemSize,lenToEnd*queue->itemSize);
            memcpy(charItem+lenToEnd*queue->itemSize,queue->base,lenFromBegin*queue->itemSize);
        }
        else
        {
            memcpy(charItem,(char*)queue->base+queue->head*queue->itemSize,len*queue->itemSize);
        }
    }

    return 0;
}

/**
  * @brief      多数据出队,指定一个最大数量，函数能返回实际数量
  * @param[in]  queue   队列
  * @param[in]  item    要出队的数据项
  * @param[in]  len     要出队的数据项数量
  * @param[out] actualLen 实际取出的数据数量
  * @return     errcode
  * @retval      0      成功
  * @retval     -1      参数异常
  * @retval     -2      数据不足len的长度
  */
int gqueue_peek_multiple_most(gqueue_t* queue, void* item,size_t len,size_t* actualLen){
    size_t qCount = gqueue_used_space(queue);
    *actualLen = len>qCount?qCount:len;
    return gqueue_peek_multiple(queue,item,*actualLen);
}

/**
  * @brief      查看队首的数据
  * @param[in]  queue   队列
  * @param[in]  item    队首的数据项
  *
  * @return     errcode
  * @retval      0      成功
  * @retval     -1      参数异常
  * @retval     -2      队列空
  */
int gqueue_peek_head(gqueue_t* queue, void* item) {
    return gqueue_peek(queue, item);
}

/**
  * @brief      查看队尾的数据
  * @param[in]  queue   队列
  * @param[in]  item    队尾的数据项
  *
  * @return     errcode
  * @retval      0      成功
  * @retval     -1      参数异常
  * @retval     -2      队列空
  */
int gqueue_peek_tail(gqueue_t* queue, void* item){
    if(queue == NULL || item == NULL)
    {
        return -1;
    }
    if(queue->isEmpty)
    {
        return -2;
    }
    memcpy(item, (char*)queue->base + (queue->tail ? (queue->tail - 1) : (queue->capcity - 1)) * queue->itemSize, queue->itemSize);

    return 0;
}

/**
  * @brief      丢弃count数量的数据    ,此函数不检查要丢弃的数量是否越界
  * @param[in]  queue   队列
  * @param[in]  count   要丢弃的数据项个数
  *
  * @return     errcode
  * @retval      0      成功
  * @retval     -1      参数异常
  * @retval     -2      队列空
  */
int gqueue_discard_multiple(gqueue_t* queue,size_t count){
    if(queue == NULL || count == 0)
    {
        return -1;
    }
    queue->head = (queue->head + count) & qCapcityMsk;

    if(queue->head == queue->tail)
    {
        queue->isEmpty = 1;
    }
    queue->isFull = 0;
    return 0;
}

/**
  * @brief      清空队列
  * @param[in]  queue   队列
  *
  * @return     errcode
  * @retval      0      成功
  * @retval     -1      失败
  */
int gqueue_clear(gqueue_t* queue) {
    if(queue == NULL)
    {
        return -1;
    }
    queue->head = 0;
    queue->tail = 0;
    queue->isEmpty = 1;
    queue->isFull = 0;
    return 0;
}

/**
  * @brief      队列初始化
  * @param[in]  queue   队列
  * @param[in]  base    指向用于队列的数组
  * @param[in]  num     数组中能存放的数据项数量,num必须为2的幂 (num&(num-1)) != 0
  * @param[in]  size    数组中每个数据项的大小
  *
  * @return     errcode
  * @retval      0      成功
  * @retval     -1      参数异常
  * @retval     -2      数据项数量不是2的幂
  */
int gqueue_init(gqueue_t* queue, void* base, size_t capcity, size_t itemSize) {
    if(queue == NULL || base == NULL)
    {
        return -1;
    }
    if((capcity&(capcity-1)) != 0)
    {
        return -2;
    }
    queue->base = base;
    queue->capcity = capcity;
    queue->itemSize = itemSize;
    queue->head = 0;
    queue->tail = 0;
    queue->isEmpty = 1;
    queue->isFull = 0;
    return 0;
}


